from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout,QSpacerItem, QSizePolicy,QHBoxLayout,QLabel
from PyQt5.QtGui import QPainter, QColor, QPen
from PyQt5.QtCore import Qt, QPointF, QTimer,QThread, pyqtSignal, QObject

from typing import Callable

import matplotlib.pyplot as plt
from datetime import datetime, timedelta

import time
import cc9d

import threading



class PlotSignal(QObject):
    plot_signal = pyqtSignal()


class soil_moisture:
    def __init__(self,target_addr:int,target_port:int,local_port:int):
        self.target_port = target_port
        self.target_addr = target_addr
        self.local_port = local_port

        self.plot_signal = PlotSignal()
        self.plot_signal.plot_signal.connect(self.show_plot)
        self.is_history_reading = False

    def regToChhol(self, sendPkgCB: Callable[[cc9d.sCc9dPkg], None])->tuple[int,int,int]:
        self.__sendPkgCB = sendPkgCB
        return (self.target_addr, self.target_port, self.local_port)

    def sendPkg(self, pkg: cc9d.sCc9dPkg):
        self.__sendPkgCB(pkg)
    
    def createPkg(self):
        pkg = cc9d.sCc9dPkg()
        pkg.to_port = self.target_port
        pkg.remote_addr = self.target_addr
        pkg.from_port = self.local_port
        return pkg

    def recvPkg(self, pkg: cc9d.sCc9dPkg):
        if self._receiveCB is not None:
            self._receiveCB(pkg)
     
    def show_plot(self):
        plt.ion() 
        fig, axs = plt.subplots(1, 1)
        fig.canvas.manager.set_window_title(f'节点{self.target_addr}土壤湿度')  
        axs.set_title(f'Soil Moisture Plot For Sensor{self.target_addr}')
        axs.set_xlabel('Time')
        axs.set_ylabel('Soil Moisture')
        axs.grid(True)
        axs.plot(self.soil_moisture.keys(), self.soil_moisture.values())
        plt.pause(0.001) 

    def readHistorty(self, current_sno, current_time):
        self.is_history_reading = True
        self.soil_moisture = {}
        self.h_pkgs = []
        self.sendPkg_num = 0
        self.recvPkg_num = 0

        def receive_h(rpkg):
            self.h_pkgs.append(rpkg)
            self.recvPkg_num +=1

        def task():
            self._receiveCB = receive_h
            # sno,sno-16,sno-32一直到sno-1024执行读取
            for i in range(0,2000,30):
                pkg = self.createPkg()
                pkg.datas = [ord('h'), current_sno-i & 0xFF, (current_sno-i >> 8) & 0xFF, 30]    
                self.sendPkg(pkg)
                self.sendPkg_num+=1
                time.sleep(0.05)
                # 这里会爆发性的收发包
            timer = 0
            print("完成发包")
            while self.recvPkg_num < self.sendPkg_num:
                time.sleep(1)
                timer+=1
                # 对5,10,15,20秒进行报告，
                if timer % 2 < 0.01:
                    print(f"读取记录已经花费了{timer}秒, 读到了{self.recvPkg_num}/{self.sendPkg_num}个包。")                    
                if timer > 10:
                    print("读取历史记录超时！")
                    break
            print("读取历史记录结束。")            

            for rpkg in self.h_pkgs:
                r_ptr = 0
                pkg_sno = rpkg.datas[r_ptr] + rpkg.datas[r_ptr+1]*256
                r_ptr+=2
                while len(rpkg.datas) > r_ptr+2 :
                    soil_moisture = rpkg.datas[r_ptr] + rpkg.datas[r_ptr+1]*256
                    r_ptr+=2
                    # 计算时间
                    time_keys= current_time - timedelta(minutes = 2 * (current_sno - pkg_sno))
                    self.soil_moisture[time_keys] = soil_moisture
                    pkg_sno-=1

            self._receiveCB = None            
            self.plot_signal.plot_signal.emit()
            self.is_history_reading = False

        thread = threading.Thread(target=task)
        thread.start()  



    def read_soil_moisture(self):
        if self.is_history_reading:
            print("正在读取历史记录，无法同时执行。")
            return
        
        # 首先使用c命令，读取土壤湿度    
        pkg = self.createPkg()
        pkg.datas = [ord('c')]       

        def receive_c(rpkg):
            tick_ms = rpkg.datas[0] + rpkg.datas[1]*256 + rpkg.datas[2]*256*256 + rpkg.datas[3]*256*256*256
            sno = rpkg.datas[4] + rpkg.datas[5]*256
            print(f"在{tick_ms}已经执行到第{sno}步。") 
            self._receiveCB = None
            # 为自身建立一个2048长度的数组，用于存储土壤湿度
            self.readHistorty(current_sno = sno-1, current_time = datetime.now())
        # 从sno开始，使用h命令读取历史记录     
        self._receiveCB = receive_c    
        self.sendPkg(pkg)     

        







